package com.jiujiu.vi;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;

import java.time.LocalDate;
import java.util.Arrays;
import java.util.Calendar;

@Service
public class ViService {

    /**
     * 计算估值
     *
     * @return
     */
    public String calcValue(String code, Double minG, Double maxG, String enter, Integer yearPre) {
        WebClient webClient = WebClient.create("https://datacenter.eastmoney.com");

        // 获取年报的净利润增长率G
        String strG = webClient.get()
                .uri(uriBuilder -> uriBuilder
                        .path("/securities/api/data/get")
                        .queryParam("type", "RPT_F10_FINANCE_MAINFINADATA")
                        .queryParam("sty", "APP_F10_MAINFINADATA")
                        .queryParam("quoteColumns", "")
                        .queryParam("filter", "(SECUCODE=\"" + code + "\")(REPORT_TYPE=\"年报\")")
                        .queryParam("p", 1)
                        .queryParam("ps", 9)
                        .queryParam("sr", -1)
                        .queryParam("st", "REPORT_DATE")
                        .queryParam("source", "HSF10")
                        .queryParam("client", "PC")
//                        .queryParam("v", "08019151281773258")
                        .build())
                .retrieve()
                .bodyToMono(String.class)
                .block();
        JSONObject jsonAllG = JSONObject.parseObject(strG);
        JSONArray jsonArrayG = jsonAllG.getJSONObject("result").getJSONArray("data");

        // 遍历净利润增长率
        int idx = 0;
        Double parentnetprofit = 0d;
        Double parentnetprofittzArray[] = new Double[5];
        Double roeArray[] = new Double[5];
        Arrays.fill(parentnetprofittzArray, 0d);
        for (Object node : jsonArrayG) {
            JSONObject jsonNode = JSONObject.from(node);
            if (0 == idx) {
                parentnetprofit = jsonNode.getDouble("PARENTNETPROFIT") / 100000000;
            }
            Double parentnetprofittz = jsonNode.getDouble("PARENTNETPROFITTZ");
            if (null == parentnetprofittz) {
                parentnetprofittz = null;
            }
            parentnetprofittzArray[idx] = parentnetprofittz;
            Double roe = jsonNode.getDouble("ROEJQ");
            if (null == roe) {
                roe = null;
            }
            roeArray[idx] = roe;
            idx++;
            if (5 == idx) {
                break;
            }
        }

        // 获取最新周期的净利润增长率G
        String strGLast = webClient.get()
                .uri(uriBuilder -> uriBuilder
                        .path("/securities/api/data/get")
                        .queryParam("type", "RPT_F10_FINANCE_MAINFINADATA")
                        .queryParam("sty", "APP_F10_MAINFINADATA")
                        .queryParam("quoteColumns", "")
                        .queryParam("filter", "(SECUCODE=\"" + code + "\")")
                        .queryParam("p", 1)
                        .queryParam("ps", 9)
                        .queryParam("sr", -1)
                        .queryParam("st", "REPORT_DATE")
                        .queryParam("source", "HSF10")
                        .queryParam("client", "PC")
//                        .queryParam("v", "09014751578438587")
                        .build())
                .retrieve()
                .bodyToMono(String.class)
                .block();
        JSONObject jsonAllGLast = JSONObject.parseObject(strGLast);
        JSONArray jsonArrayGLast = jsonAllGLast.getJSONObject("result").getJSONArray("data");

        // 净利润增长率，最新
        JSONObject jsonGLast = jsonArrayGLast.getJSONObject(0);
        String name = jsonGLast.getString("SECURITY_NAME_ABBR");
        Double parentnetprofittzLastOne = jsonGLast.getDouble("PARENTNETPROFITTZ");
        Double parentnetprofittzLast = parentnetprofittzLastOne;
        if (null == parentnetprofittzLast) {
            parentnetprofittzLast = jsonGLast.getDouble("KCFJCXSYJLRTZ");
        }
        if (null == parentnetprofittzLast) {
            parentnetprofittzLast = 0d;
        }
        Double pfLast3 = Math.pow((1 + parentnetprofittzLast / 100), 3);
        String reportDate = jsonGLast.getString("REPORT_DATE");

        // 获取总股本TS
        String strTS = webClient.get()
                .uri(uriBuilder -> uriBuilder
                        .path("securities/api/data/v1/get")
                        .queryParam("reportName", "RPT_F10_EH_EQUITY")
                        .queryParam("columns", "TOTAL_SHARES")
                        .queryParam("quoteColumns", "")
                        .queryParam("filter", "(SECUCODE=\"" + code + "\")")
                        .queryParam("pageNumber", 1)
                        .queryParam("pageSize", 7)
                        .queryParam("sortTypes", -1)
                        .queryParam("sortColumns", "END_DATE")
                        .queryParam("source", "HSF10")
                        .queryParam("client", "PC")
//                        .queryParam("v", "08569023780789453")
                        .build())
                .retrieve()
                .bodyToMono(String.class)
                .block();
        JSONObject jsonTS = JSONObject.parseObject(strTS);
        JSONArray jsonArrayTS = jsonTS.getJSONObject("result").getJSONArray("data");

        // 总股本，最新
        JSONObject jsonTSLast = jsonArrayTS.getJSONObject(0);
        Double totalShares = jsonTSLast.getDouble("TOTAL_SHARES") / 100000000;

        // 获取总市值MC
        String strMC = webClient.get()
                .uri(uriBuilder -> uriBuilder
                        .path("securities/api/data/v1/get")
                        .queryParam("reportName", "RPT_DMSK_NEWINDICATOR")
                        .queryParam("columns", "SECURITY_CODE,SECUCODE")
                        .queryParam("quoteColumns", "f9~01~SECURITY_CODE~PE_DYNAMIC,f114~01~SECURITY_CODE~PE_STATIC,f115~01~SECURITY_CODE~PE_TTM,f23~01~SECURITY_CODE~PB_NEW_NOTICE,f20~01~SECURITY_CODE~TOTAL_MARKET_CAP")
                        .queryParam("filter", "(SECUCODE=\"" + code + "\")")
                        .queryParam("pageNumber", 1)
                        .queryParam("pageSize", 1)
                        .queryParam("sortTypes", "")
                        .queryParam("sortColumns", "")
                        .queryParam("source", "HSF10")
                        .queryParam("client", "PC")
//                        .queryParam("v", "03885690200770675")
                        .build())
                .retrieve()
                .bodyToMono(String.class)
                .block();
        JSONObject jsonMC = JSONObject.parseObject(strMC);
        JSONArray jsonArrayMC = jsonMC.getJSONObject("result").getJSONArray("data");

        // 总市值，最新
        JSONObject jsonMCLast = jsonArrayMC.getJSONObject(0);
        Double totalMarketCap = jsonMCLast.getDouble("TOTAL_MARKET_CAP") / 100000000;

        // 获取预测净利润增长率PreTZ
        String predictYear = "";
        if (null != yearPre) {
            String strPreTZ = webClient.get()
                    .uri(uriBuilder -> uriBuilder
                            .path("securities/api/data/v1/get")
                            .queryParam("reportName", "RPT_HSF10_RESPREDICT_COUNTSTATISTICS")
                            .queryParam("columns", "YEAR,PARENT_NETPROFIT")
                            .queryParam("quoteColumns", "")
                            .queryParam("filter", "(SECUCODE=\"" + code + "\")")
                            .queryParam("pageNumber", 1)
                            .queryParam("pageSize", 200)
                            .queryParam("sortTypes", 1)
                            .queryParam("sortColumns", "RANK")
                            .queryParam("source", "HSF10")
                            .queryParam("client", "PC")
//                        .queryParam("v", "08015583645663806")
                            .build())
                    .retrieve()
                    .bodyToMono(String.class)
                    .block();
            JSONObject jsonPreTZ = JSONObject.parseObject(strPreTZ);
            JSONArray jsonArrayPreTZ = jsonPreTZ.getJSONObject("result").getJSONArray("data");

            // 总市值，最新
            Double pfPre = 0d;
            Double pfYear[] = new Double[3];
            Arrays.fill(pfYear, 0d);
            for (Object node : jsonArrayPreTZ) {
                JSONObject jsonNode = JSONObject.from(node);
                Integer year = jsonNode.getInteger("YEAR");
                Double parentNetprofit = jsonNode.getDouble("PARENT_NETPROFIT");
                if (year.equals(yearPre - 1)) {
                    pfPre = parentNetprofit;
                }
                else if (yearPre.equals(year)) {
                    pfYear[0] = parentNetprofit;
                }
                else if (yearPre.equals(year - 1)) {
                    pfYear[1] = parentNetprofit;
                }
                else if (yearPre.equals(year - 2)) {
                    pfYear[2] = parentNetprofit;
                }
            }
            if (!pfPre.equals(0d) && !pfYear[0].equals(0d) && !pfYear[1].equals(0d) && !pfYear[2].equals(0d)) {
                Double pf1 = (pfYear[0] - pfPre) / pfPre;
                Double pf2 = (pfYear[1] - pfYear[0]) / pfYear[0];
                Double pf3 = (pfYear[2] - pfYear[1]) / pfYear[1];
                pfLast3 = (1 + pf1) * (1 + pf2) * (1 + pf3);
                parentnetprofittzLast = (Math.pow(pfLast3, 1d / 3d) - 1) * 100;
                predictYear = "(预测"+ yearPre + "三年)";
            }
        }

        // 计算估值
        // 近五年平均净利润增长率
        Double sumTZ = 0d;
        Double avgTZ = 0d;
        int countTZ = 0;
        for (Double tz : parentnetprofittzArray) {
            if (null != tz) {
                sumTZ += tz;
                countTZ++;
            }
        }
        avgTZ = sumTZ / countTZ;
        // 近五年平均净资产收入率
        Double sumROE = 0d;
        Double avgROE = 0d;
        int countROE = 0;
        for (Double roe : roeArray) {
            if (null != roe) {
                sumROE += roe;
                countROE++;
            }
        }
        avgROE = sumROE / countROE;

        // 未来第三年预计净利润
        Double fit3 = parentnetprofit * pfLast3;

        // 预计净利润折扣50%
        Double fit3P50 = fit3 / 2;

        // 无风险收益率
        Double avgG = (minG + maxG) / 2d;
        int minGR = (int) (100 / minG);
        int maxGR = (int) (100 / maxG);
        int avgGR = (int) (100 / avgG);

        // 预计市值
        Double minValueAll = fit3 * 100 / minG;
        Double maxValueAll = fit3 * 100 / maxG;
        Double avgValueAll = fit3 * 100 / avgG;

        // 预计市值折扣50%
        Double minValueAllP50 = minValueAll / 2;
        Double maxValueAllP50 = maxValueAll / 2;
        Double avgValueAllP50 = avgValueAll / 2;

        // 预计股价
        Double minValue = minValueAll / totalShares;
        Double maxValue = maxValueAll / totalShares;
        Double avgValue = avgValueAll / totalShares;

        // 预计股价折扣50%
        Double minValueP50 = minValue / 2;
        Double maxValueP50 = maxValue / 2;
        Double avgValueP50 = avgValue / 2;

        // 当前价格
        Double currValue = totalMarketCap / totalShares;
        Double minCurr = (currValue - minValueP50) / Math.abs(minValueP50) * 100;
        Double maxCurr = (currValue - maxValueP50) / Math.abs(maxValueP50) * 100;
        Double avgCurr = (currValue - avgValueP50) / Math.abs(avgValueP50) * 100;

        String result = "";
        result += name + ",," + code + "\n" + enter; // 股票名称
        result += "报告期：" + reportDate + String.format("【%.3f】", parentnetprofittzLastOne) + predictYear + "\n" + enter; // 报告期
        result += "前一年财报净利润," + "P," + String.format("%.3f\n" + enter, parentnetprofit);
        result += "近五年平均净利润增长率," + ","
                + String.format("%.3f,", parentnetprofittzLast)
                + (null != parentnetprofittzArray[0]? String.format("%.3f,", parentnetprofittzArray[0]): "--,")
                + (null != parentnetprofittzArray[1]? String.format("%.3f,", parentnetprofittzArray[1]): "--,")
                + (null != parentnetprofittzArray[2]? String.format("%.3f,", parentnetprofittzArray[2]): "--,")
                + (null != parentnetprofittzArray[3]? String.format("%.3f,", parentnetprofittzArray[3]): "--,")
                + (null != parentnetprofittzArray[4]? String.format("%.3f,", parentnetprofittzArray[4]): "--,")
                + String.format("%.3f\n" + enter, avgTZ);
        result += "近五年净资产收益率," + ",,"
                + (null != roeArray[0]? String.format("%.3f,", roeArray[0]): "--,")
                + (null != roeArray[1]? String.format("%.3f,", roeArray[1]): "--,")
                + (null != roeArray[2]? String.format("%.3f,", roeArray[2]): "--,")
                + (null != roeArray[3]? String.format("%.3f,", roeArray[3]): "--,")
                + (null != roeArray[4]? String.format("%.3f,", roeArray[4]): "--,")
                + String.format("%.3f\n" + enter, avgROE);
        result += "未来第三年预计净利润," + "," + String.format("%.3f\n" + enter, fit3);
        result += "预计净利润折扣50%," + "," + String.format("%.3f\n" + enter, fit3P50);
        result += "无风险收益率," + "g,"
                + String.format("%.3f,", minG)
                + String.format("%d,", minGR)
                + String.format("%.3f,", maxG)
                + String.format("%d,", maxGR)
                + String.format("%.3f,", avgG)
                + String.format("%d\n" + enter, avgGR);
        result += "预计市值," + ","
                + String.format("%.3f,,", minValueAll)
                + String.format("%.3f,,", maxValueAll)
                + String.format("%.3f\n" + enter, avgValueAll);
        result += "预计市值折扣50%," + ","
                + String.format("%.3f,,", minValueAllP50)
                + String.format("%.3f,,", maxValueAllP50)
                + String.format("%.3f\n" + enter, avgValueAllP50);
        result += "总股本," + ","
                + String.format("%.3f,,", totalShares)
                + String.format("%.3f,,", totalShares)
                + String.format("%.3f\n" + enter, totalShares);
        result += "预计股价," + ","
                + String.format("%.3f,,", minValue)
                + String.format("%.3f,,", maxValue)
                + String.format("%.3f\n" + enter, avgValue);
        result += "预计股价折扣50%," + ","
                + String.format("%.3f,,", minValueP50)
                + String.format("%.3f,,", maxValueP50)
                + String.format("%.3f\n" + enter, avgValueP50);
        result += LocalDate.now() + "市值," + ","
                + String.format("%.3f,,", totalMarketCap)
                + String.format("%.3f,,", totalMarketCap)
                + String.format("%.3f\n" + enter, totalMarketCap);
        result += LocalDate.now() + "价格," + ","
                + String.format("%.3f,", currValue)
                + String.format("%.3f,", minCurr)
                + String.format("%.3f,", currValue)
                + String.format("%.3f,", maxCurr)
                + String.format("%.3f,", currValue)
                + String.format("%.3f\n" + enter, avgCurr);

        return result;
    }

}
